/*
 * Package il.ac.biu.cs.grossmm.test.cppToFooAdapter
 * File Client.java
 * 
 * This is a part of presence service framework API. 
 * See javadoc for more information.
 *  
 * Copyright (C) 2006 Grossmann Mark
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package il.ac.biu.cs.grossmm.tests.fooClients;

import il.ac.biu.cs.grossmm.foo.format.*;
import il.ac.biu.cs.grossmm.foo.format.PresenceDoc.Tuple;
import il.ac.biu.cs.grossmm.foo.protocol.*;
import il.ac.biu.cs.grossmm.tests.fooAdapters.Server;

import java.awt.SplashScreen;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.HashSet;
import java.util.Random;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Flooder extends DirectClient {

	private static final String rulesDocType = "foo.WatcherRulesDoc";

	private static final String presenceDocType = "foo.PresenceDoc";
	
	
	public static volatile long publish_rate;
	public static volatile long notify_rate;
	

	static Random random = new Random();

	boolean log = false;
	boolean notify_log = false;

	PresenceDoc[] presenceDocs = new PresenceDoc[1001];


	Flooder()
	{

		HashSet<String> set = new HashSet<String>();

		Tuple[] ts = new Tuple[3];
		for (int i = 0; i < 3; i++)
			ts[i] = genTuple(set);

		for (int i = 0; i < presenceDocs.length; i++) {

			ts[random.nextInt(3)] = genTuple(set);

			for (int j = 0; j < 3; j++)
				ts[j].setAddress("address" + j + "@example.com");

			presenceDocs[i] =
				new PresenceDoc("xxx",
					new Mood(random.nextInt(10), random.nextInt(10),
						random.nextInt(10), random.nextInt(10)),
					new Activities(Activity.values()[random.nextInt(10)],
						Activity.values()[random.nextInt(10)]), "kitchen"
						+ (i % 3), "home" + (i % 5), ts);
		}
	}

	/**
	 * @param set
	 * @param i
	 */
	private Tuple genTuple(HashSet<String> set)
	{
		Tuple t;

		set.clear();
		while (random.nextInt(4) < 3) {
			set.add("capability" + random.nextInt(10));
		}

		int d = random.nextInt(2);
		t =
			new Tuple("1", random.nextInt(4) / 4f, "x", OnlineStatus.values()[d
				* d], "class" + (d + d), Capabilities.of(set));

		return t;
	}

	long tresp = System.currentTimeMillis();
	int respcount = 0;
	int respcount0 = 0;
	
	
	@Override
	protected Response requestReceived(Request request)
	{

		if (!(request instanceof NotifyRequest)) {
			System.out.println("<=== " + request);
			System.out.println("Not a notification");
			System.out.println("---> " + ResponseCodes.BAD_REQUEST);
			return new Response(request, ResponseCodes.BAD_REQUEST);
		}

		if (notify_log) {
			System.out.println("<=== " + request);
			NotifyRequest nr = (NotifyRequest) request;

			System.out.println("---> 200 (" + request.getCommand() + ")");
		}
		
		respcount++;
		
		if( respcount % 100 == 0 && System.currentTimeMillis() - tresp >1000) {
			notify_rate = 1000*(respcount-respcount0) / (System.currentTimeMillis() -tresp );
			
			//System.out.println("Resp rate: "+ 1000*(respcount-respcount0) / (System.currentTimeMillis() -tresp ));
			respcount0 = respcount;
			tresp = System.currentTimeMillis();
		}

		return request.okResponse();
	}

	void send(Request request) throws IOException, InterruptedException
	{
		// Thread.sleep(1000);

		if (log) {
			System.out.println("===> " + request);

			Response response = sendRequest(request);

			System.out.println("<--- " + response + "(" + request.getCommand()
				+ ")\n");

		} else
			sendRequest(request);
	}

	public static void main(String[] args) throws UnknownHostException,
		IOException, InterruptedException
	{
		Level level = Level.OFF;
		
		Logger logger = Logger.getLogger("");
		logger.setLevel(level);
		Handler[] hh = logger.getHandlers();
		for (Handler h : hh)
			h.setLevel(level);

		new Thread() {
			public void run()
			{
				try {
					Server.main(null);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}.start();
		
		

		Thread.sleep(10000);
		
		new Thread() {
			public void run()
			{
				try {
					PingClient.main(null);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}.start();
		

		Flooder client = new Flooder();

		client.connectTo("localhost", 4004);

		System.out.println("Connected.");
		
	    //Thread.sleep(600000);
		
//		for( int p=0; p<100000; p++ ) {
//			client.send(new PingRequest());
//			if( p % 1000 == 0 )
//				System.out.println("pinging: "+p);
//		}

		Response resp;

		System.out.println("Logging users ");

		int Nsub = 100;
		int K = 20;
		int Nagg = 1;
		
		int Npub = Nsub/K;
		
		int COUNT = 100000000;

		for (int i = 0; i < Npub; i++) {
			client.send(new HelloRequest("Bob" + i, "boob"));
			if (i % 1000 == 0)
				System.out.print(".");
		}

		System.out.println("Done.");

		WatcherRulesDoc rdoc = new WatcherRulesDoc();
		rdoc.addPersonalRules(null, null, true);
		String rds = rdoc.serialize();

		System.out.println("Publishing presence ");
		
		long t = System.currentTimeMillis();
		int n=0;
		
		String def = client.presenceDocs[0].serialize();
		
		int toSleep = 1000;

		for (int i = 0; i <= COUNT; i++) {

			int j = i % (Npub/Nagg);
			
//			if( i%1000==0 )
//				System.out.println("publictaions: "+i);
			
//			if( i % (i/1000+1) == 0 ) {
//				Thread.sleep(5);
//			}
			
//			if( i%3==0)
//				Thread.sleep(20);
			
			if (i < Npub) {
				client.send(new PublishRequest("0", "Bob" + j, 1800,
					rulesDocType, rdoc.serialize()));
			}
			
			
			int docNum = random.nextInt(client.presenceDocs.length);
			PresenceDoc doc = client.presenceDocs[docNum];
			
			for( int k=0; k<3; k++ )
				doc.getTuples()[k].setAddress("bob"+j+"@x.com");
			
			doc.setLocation("dst"+i);
			
			client.send(new PublishRequest("1", "Bob" + j, 1800,
				presenceDocType, doc.serialize()));

			
			if (i>=Npub && i<2*Npub) {
				// System.out.println("\n\n\n\n\n");
				for( int jk=0; jk<K; jk++ )
				client.send(new SubscribeRequest("Bob"+j, "Bob"+random.nextInt(Npub), 60));
			}

			// Thread.sleep(0, toSleep*(COUNT-i)/COUNT);
			
			
			
			if( i%1000 == 0 ) {
				long t1 = System.currentTimeMillis();
				if( t1-t > 1000 ) {
					publish_rate = 1000*(i-n)/(t1-t);
//					System.out.println("speed: "+1000*(i-n)/(t1-t));
//					System.out.println("== PAUSE "+i);
//					Thread.sleep(10000);
//					System.out.println("== RESUME");
					n=i;
					t=System.currentTimeMillis();
				}
			}
		}

		System.out.println("Done.");


		 client.disconnect();
	}

}
